"""Authentication & user related API routes."""

from __future__ import annotations

import secrets
import os
from pathlib import Path
from datetime import datetime

from fastapi import APIRouter, Depends, HTTPException, status, UploadFile, File
from sqlalchemy.orm import Session

from app.database import get_database_session as get_db
from app.models.user import User
from app.schemas.user import (
    UserRegister,
    UserLogin,
    GuestLoginRequest,
    UserProfile,
    TokenResponse,
    PasswordUpdate,
    AvatarUrlUpdate,
    Message,
)
from app.utils.auth import (
    get_password_hash,
    verify_password,
    create_access_token,
    get_current_user,
    get_registered_user,
)
from app.config import settings

router = APIRouter()


@router.post("/register", response_model=UserProfile, status_code=201)
def register(payload: UserRegister, db: Session = Depends(get_db)):
    # Check existing username
    existing = db.query(User).filter(User.username == payload.username).first()
    if existing:
        raise HTTPException(status_code=409, detail="Username already exists")

    user = User(
        username=payload.username.strip(),
        password_hash=get_password_hash(payload.password),
        is_guest=False,
        is_active=True,
    )
    db.add(user)
    db.commit()
    db.refresh(user)
    return user


@router.post("/login", response_model=TokenResponse)
def login(payload: UserLogin, db: Session = Depends(get_db)):
    user = db.query(User).filter(User.username == payload.username).first()
    if not user or not verify_password(payload.password, user.password_hash or ""):
        raise HTTPException(status_code=401, detail="Incorrect username or password")

    token = create_access_token(
        {"sub": str(user.id), "username": user.username, "is_guest": user.is_guest}
    )
    return TokenResponse(
        access_token=token,
        expires_in=settings.ACCESS_TOKEN_EXPIRE_MINUTES * 60,
        is_guest=user.is_guest,
        username=user.username,
    )


@router.post("/guest", response_model=TokenResponse, status_code=201)
def guest_login(db: Session = Depends(get_db)):
    # Generate a unique guest username
    for _ in range(5):
        candidate = f"guest_{secrets.token_hex(3)}"
        if not db.query(User).filter(User.username == candidate).first():
            username = candidate
            break
    else:  # pragma: no cover - extremely unlikely
        raise HTTPException(status_code=500, detail="Unable to allocate guest username")

    user = User(username=username, is_guest=True, is_active=True)
    db.add(user)
    db.commit()
    db.refresh(user)

    token = create_access_token(
        {"sub": str(user.id), "username": user.username, "is_guest": True}
    )
    return TokenResponse(
        access_token=token,
        expires_in=settings.ACCESS_TOKEN_EXPIRE_MINUTES * 60,
        is_guest=True,
        username=username,
    )


@router.get("/me", response_model=UserProfile)
def me(current_user: User = Depends(get_current_user)):
    return current_user


@router.put("/password", response_model=Message)
def update_password(
    payload: PasswordUpdate,
    user: User = Depends(get_registered_user),
    db: Session = Depends(get_db),
):
    if not verify_password(payload.old_password, user.password_hash or ""):
        raise HTTPException(status_code=400, detail="Old password incorrect")
    user.password_hash = get_password_hash(payload.new_password)
    db.add(user)
    db.commit()
    return Message(message="Password updated")


@router.put("/username", response_model=Message)
def update_username(
    payload: dict,
    user: User = Depends(get_registered_user),
    db: Session = Depends(get_db),
):
    new_username = payload.get("new_username", "").strip()
    if not new_username:
        raise HTTPException(status_code=400, detail="New username cannot be empty")

    # Check if username already exists
    existing = (
        db.query(User).filter(User.username == new_username, User.id != user.id).first()
    )
    if existing:
        raise HTTPException(status_code=409, detail="Username already exists")

    user.username = new_username
    db.add(user)
    db.commit()
    return Message(message="Username updated")


@router.post("/logout", response_model=Message)
def logout():  # Stateless JWT -> client discards token
    return Message(message="Logged out (client token discarded)")


@router.post("/avatar/upload", response_model=UserProfile)
async def upload_avatar(
    file: UploadFile = File(...),
    user: User = Depends(get_registered_user),
    db: Session = Depends(get_db),
):
    """上传头像图片"""
    # 验证文件类型
    allowed_types = ["image/jpeg", "image/png", "image/gif", "image/webp"]
    if file.content_type not in allowed_types:
        raise HTTPException(
            status_code=400, detail="只支持 JPG, PNG, GIF, WEBP 格式的图片"
        )

    # 验证文件大小（最大2MB）
    content = await file.read()
    if len(content) > 2 * 1024 * 1024:
        raise HTTPException(status_code=400, detail="图片大小不能超过2MB")

    # 创建用户头像目录
    avatar_dir = Path("data/avatars") / str(user.id)
    avatar_dir.mkdir(parents=True, exist_ok=True)

    # 获取文件扩展名
    filename_str = file.filename or "avatar.jpg"
    ext = filename_str.split(".")[-1] if "." in filename_str else "jpg"
    filename = f"avatar.{ext}"
    filepath = avatar_dir / filename

    # 保存文件
    with open(filepath, "wb") as f:
        f.write(content)

    # 更新用户头像URL（使用相对路径）
    user.avatar_url = f"/avatars/{user.id}/{filename}"
    db.add(user)
    db.commit()
    db.refresh(user)

    return user


@router.put("/avatar/url", response_model=UserProfile)
def update_avatar_url(
    payload: AvatarUrlUpdate,
    user: User = Depends(get_registered_user),
    db: Session = Depends(get_db),
):
    """设置在线头像URL"""
    # 简单验证URL格式
    url = payload.avatar_url.strip()
    if not (url.startswith("http://") or url.startswith("https://")):
        raise HTTPException(status_code=400, detail="请输入有效的HTTP/HTTPS URL")

    user.avatar_url = url
    db.add(user)
    db.commit()
    db.refresh(user)

    return user


@router.delete("/avatar", response_model=Message)
def delete_avatar(
    user: User = Depends(get_registered_user),
    db: Session = Depends(get_db),
):
    """删除头像（恢复默认）"""
    # 如果是本地文件，尝试删除
    if user.avatar_url and user.avatar_url.startswith("/avatars/"):
        avatar_path = Path("data") / user.avatar_url.lstrip("/")
        if avatar_path.exists():
            avatar_path.unlink()

    user.avatar_url = None
    db.add(user)
    db.commit()

    return Message(message="头像已删除")
